<?php
// +----------------------------------------------------------------------
// | RXThinkCMF敏捷开发框架 [ 赋能开发者，助力企业发展 ]
// +----------------------------------------------------------------------
// | 版权所有 2018~2023 南京RXThinkCMF研发中心
// +----------------------------------------------------------------------
// | Licensed LGPL-3.0 RXThinkCMF并不是自由软件，未经许可禁止去掉相关版权
// +----------------------------------------------------------------------
// | 官方网站: https://www.rxthink.cn
// +----------------------------------------------------------------------
// | Author: @牧羊人 团队荣誉出品
// +----------------------------------------------------------------------
// | 版权和免责声明:
// | 本团队对该软件框架产品拥有知识产权（包括但不限于商标权、专利权、著作权、商业秘密等）
// | 均受到相关法律法规的保护，任何个人、组织和单位不得在未经本团队书面授权的情况下对所授权
// | 软件框架产品本身申请相关的知识产权，禁止用于任何违法、侵害他人合法权益等恶意的行为，禁
// | 止用于任何违反我国法律法规的一切项目研发，任何个人、组织和单位用于项目研发而产生的任何
// | 意外、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其造成的损失 (包括但不限于直接、间接、
// | 附带或衍生的损失等)，本团队不承担任何法律责任，本软件框架禁止任何单位和个人、组织用于
// | 任何违法、侵害他人合法利益等恶意的行为，如有发现违规、违法的犯罪行为，本团队将无条件配
// | 合公安机关调查取证同时保留一切以法律手段起诉的权利，本软件框架只能用于公司和个人内部的
// | 法律所允许的合法合规的软件产品研发，详细声明内容请阅读《框架免责声明》附件；
// +----------------------------------------------------------------------

namespace app\admin\service;

use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;
use app\admin\model\Student;
use app\admin\model\User;
use Darabonba\OpenApi\Models\Config;
use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;

/**
 * 用户管理-服务类
 * @author 牧羊人
 * @since 2020/11/19
 * Class UserService
 * @package app\admin\service
 */
class UserService extends BaseService
{
    /**
     * 构造函数
     * @author 牧羊人
     * @since 2020/11/19
     * UserService constructor.
     */
    public function __construct()
    {
        $this->model = new User();
    }

    /**
     * 获取数据列表
     * @return array
     * @since 2020/11/19
     * @author 牧羊人
     */
    public function getList($page = 0, $limit = 0)
    {
        $param = request()->param();

        // 查询条件
        $map = [];

        // 用户账号
        $username = getter($param, "username");
        if ($username) {
            $map[] = ["username", 'like', "%{$username}%"];
        }
        // 用户姓名
        $realname = getter($param, "realname");
        if ($realname) {
            $map[] = ['realname', 'like', "%{$realname}%"];
        }
        // 用户性别
        $gender = getter($param, "gender");
        if ($gender) {
            $map[] = ['gender', '=', $gender];
        }
        //地区
        $province_code = getter($param, "province_code");
        $city_code = getter($param, "city_code");
        $district_code = getter($param, "district_code");
        $streets_code = getter($param, "streets_code");
        if($streets_code){
            $map[] = ['streets_code', '=', $streets_code];
        }elseif ($district_code){
            $map[] = ['district_code', '=', $district_code];
        }elseif ($city_code){
            $map[] = ['city_code', '=', $city_code];
        }elseif ($province_code){
            $map[] = ['province_code', '=', $province_code];
        }
        //学校
        $schoole_id = getter($param, "schoole_id");
        if ($schoole_id) {
            $map[] = ['schoole_id', '=', $schoole_id];
        }
        //角色
        $role_ids = $param['role_id'] ?? [];
        if ($role_ids) {
            $admin_ids = db('user_role')->where([['role_id', 'in', $role_ids]])->column('user_id');
            $map[] = ['id', 'in', $admin_ids];
        }
        $page = $page ?: request()->param('page', 1);
        $limit = $limit ?: request()->param('limit', 20);
        $limit = $limit > 50 ? 50 : $limit;
        $sort = 'id desc';
        $result = $this->model->where($map)->where('mark',1)->order($sort)->page($page, $limit)->column("id");
        $list = [];
        if (is_array($result)) {
            foreach ($result as $val) {
                $info = $this->model->getInfo($val);
                $list[] = $info;
            }
        }

        //获取数据总数
        $count = $this->model->where($map)->where('mark',1)->count();
        //返回结果
        $message = array(
            "msg" => '操作成功',
            "code" => 0,
            "data" => $list,
            "count" => $count,
        );
        return $message;
    }

    /**
     * 添加或编辑
     * @return mixed
     * @throws \think\db\exception\BindParamException
     * @throws \think\exception\PDOException
     * @since 2020/11/19
     * @author 牧羊人
     */
    public function edit()
    {
        // 请求参数
        $data = request()->param();
        // 用户名
        $username = trim($data['username']);
        // 密码
        $password = trim($data['password'] ?? '');
        // 用户ID
        $id = getter($data, "id", 0);
        // 添加时设置密码
        if (empty($id)) {
            if(strlen($password)<6 || strlen($password)>18){
                return message("密码长度必须在6-18位之间", false);
            }
            $data['password'] = get_password($password . $username);
            // 用户名重复性验证
            $count = $this->model
                ->where("username", '=', $username)
                ->where("mark", "=", 1)
                ->count();
            if ($count > 0) {
                return message("系统中已存在相同的用户名", false);
            }
        } else {
            // 用户名重复性验证
            $count = $this->model
                ->where("username", '=', $username)
                ->where("id", "<>", $data['id'])
                ->where("mark", "=", 1)
                ->count();
            if ($count > 0) {
                return message("系统中已存在相同的用户名", false);
            }
            // 获取用户信息
            $info = $this->model->getInfo($id);
            if (!$info) {
                return message("用户信息不存在", false);
            }
            //密码6-18位
            if($password){
                if(strlen($password)<6 || strlen($password)>18){
                    return message("密码长度必须在6-18位之间", false);
                }
                $data['password'] = get_password($password . $username);
            }else{
                unset($data['password']);
            }
        }

        // 头像处理
        $avatar = getter($data, 'avatar');
        if (!empty($avatar)) {
            if (strpos($avatar, "temp")) {
                $data['avatar'] = save_image($avatar, 'user');
            } else {
                $data['avatar'] = str_replace(IMG_URL, "", $data['avatar']);
            }
        }

        // 出生日期
        if (isset($data['birthday']) && $data['birthday']) {
            $data['birthday'] = strtotime($data['birthday']);
        }

        // 城市数据处理
        $city = isset($data['city']) ? $data['city'] : [];
        if (!empty($city)) {
            $data['province_code'] = $city[0];
            $data['city_code'] = $city[1];
            $data['district_code'] = $city[2];
        } else {
            $data['province_code'] = 0;
            $data['city_code'] = 0;
            $data['district_code'] = 0;
        }
        unset($data['city']);

        //特殊角色和城市数据处理 $special_role = [5, 6, 7, 8];//市级管理员、县(区)级管理、街道办管理员、学校管理员
        if(in_array(5, $data['role_ids']) && !$data['city_code']){
            return message('市级管理员必须选择所在市', false);
        }
        if(in_array(6, $data['role_ids']) && !$data['district_code']){
            return message('县(区)级管理员必须选择所在县(区)', false);
        }
        if(in_array(7, $data['role_ids']) && (!isset($data['streets_code']) || !$data['streets_code'])){
            return message('街道办管理员必须选择所在街道(镇)', false);
        }
        if((in_array(8, $data['role_ids']) || in_array(10, $data['role_ids'])) && (!isset($data['schoole_id']) || !$data['schoole_id'])){
            return message('学校管理员/学校老师必须选择所属学校', false);
        }

        $error = "";
        $result = $this->model->edit($data, $error);
        if (!$result) {
            return message($error, false);
        }

        // 删除用户整体缓存
        $this->model->cacheDAll();

        // 删除已存在的用户角色关系数据
        $userRoleService = new UserRoleService();
        $userRoleService->deleteUserRole($result);
        // 插入用户角色关系数据
        $userRoleService->insertUserRole($result, $data['role_ids']);
        return message();
    }

    /**
     * 获取用户信息
     * @param $userId
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @since 2020/11/19
     * @author 牧羊人
     */
    public function getUserInfo($userId)
    {
        $userInfo = $this->model->getInfo($userId);

        // 返回参数
        $result = array();
        $result['id'] = $userInfo['id'];
        $result['avatar'] = $userInfo['avatar'];
        $result['realname'] = $userInfo['realname'];
        $result['nickname'] = $userInfo['nickname'];
        $result['gender'] = $userInfo['gender'];
        $result['mobile'] = $userInfo['mobile'];
        $result['email'] = $userInfo['email'];
        $result['address'] = $userInfo['address'];
        $result['intro'] = $userInfo['intro'];
        $result['roles'] = [];
        $result['authorities'] = [];

        // 权限节点列表
        $menuService = new MenuService();
        $permissionList = $menuService->getPermissionsList($userId);
        $result['permissionList'] = $permissionList;
        return message("操作成功", true, $result);
    }

    /**
     * 更新个人资料
     * @param $userId 用户ID
     * @return array
     * @throws \think\db\exception\BindParamException
     * @throws \think\exception\PDOException
     * @author 牧羊人
     * @since 2021/4/23
     */
    public function updateUserInfo($userId)
    {
        // 参数
        $param = request()->param();
        // 个人信息
        $data = [
            'id' => $userId,
            'realname' => $param['realname'],
            'nickname' => $param['nickname'],
            'gender' => $param['gender'],
            'mobile' => $param['mobile'],
            'email' => $param['email'] ?? '',
            'intro' => $param['intro'] ?? '',
        ];
        // 头像处理
        $avatar = isset($param['avatar']) ? $param['avatar'] : "";
        if (strpos($avatar, "data:image") !== false) {
            $expData = explode(';', $avatar);
            $fileInfo = explode('/', $expData[0]);
            $fileExt = $fileInfo[1] == 'jpeg' ? 'jpg' : $fileInfo[1];
            // 文件存储路径
            $filePath = create_image_path("user", $fileExt);

            // 获取图片流
            $item = explode(',', $avatar);
            file_put_contents(ATTACHMENT_PATH . $filePath, base64_decode($item[1]));

            $data['avatar'] = $filePath;
        } else {
            $data['avatar'] = str_replace(IMG_URL, "", $param['avatar']);
        }
        $result = $this->model->edit($data);
        if (!$result) {
            return message("更新资料信息失败", false);
        }
        return message("更新资料信息成功");
    }

    /**
     * 修改密码
     * @param $userId 用户ID
     * @return mixed
     * @throws \think\db\exception\BindParamException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     * @since 2020/11/19
     * @author 牧羊人
     */
    public function updatePwd($userId)
    {
        // 获取参数
        $param = request()->param();
        // 原始密码
        $oldPassword = trim(getter($param, "oldPassword"));
        if (!$oldPassword) {
            return message("旧密码不能为空", false);
        }
        // 新密码
        $newPassword = trim(getter($param, "newPassword"));
        if (!$newPassword) {
            return message("新密码不能为空", false);
        }
        if ($newPassword == $oldPassword) {
            return message("新密码与旧密码一致，无需修改", false);
        }
        $userInfo = db('user')->where('id', $userId)->find();
        if (!$userInfo) {
            return message("用户信息不存在", false);
        }
        $oldMd5Pwd = get_password($oldPassword . $userInfo['username']);
        if ($userInfo['password'] != $oldMd5Pwd) {
            return message("旧密码输入不正确", false);
        }
        $newMd5Pwd = get_password($newPassword . $userInfo['username']);
        $item = [
            'id' => $userId,
            'password' => $newMd5Pwd,
        ];
        $result = $this->model->edit($item);
        if (!$result) {
            return message("修改失败", false);
        }
        $this->model->deleteCache('pwd_raw:' . $oldMd5Pwd);
        $this->model->setCache('pwd_raw:' . $newMd5Pwd, $newPassword);
        return message("修改成功");
    }

    /**
     * 重置密码
     * @return mixed
     * @throws \think\db\exception\BindParamException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     * @author 牧羊人
     * @since 2020/11/19
     */
    public function resetPwd()
    {
        // 获取参数
        $param = request()->param();
        // 用户ID
        $userId = getter($param, "id");
        if (!$userId) {
            return message("用户ID不能为空", false);
        }
        $userInfo = $this->model->getInfo($userId);
        if (!$userInfo) {
            return message("用户信息不存在", false);
        }
        $item = [
            'id' => $param['id'],
            'password' => get_password("123456" . $userInfo['username']),
        ];
        $result = $this->model->edit($item);
        if (!$result) {
            return message("重置密码失败", false);
        }
        return message("重置密码成功");
    }

    //根据区县code 获取 街道列表streets_code
    public function getStreetsList()
    {
        // 获取参数
        $district_code = request()->param('district_code', '');
        if(!$district_code)
            return message("缺少district_code", false);

        $data = db('city_level4')->field('id as streets_code, pid, ext_name')->where(['pid' => $district_code])->select();
        return message("操作成功", true, $data);
    }

    //获取学校列表
    public function getSchoolList()
    {
        // 获取参数
        $streets_code = request()->param('streets_code', '');
        if(!$streets_code)
            return message("缺少streets_code", false);

        $data = db('schoole')->where(['streets_code' => $streets_code, 'mark' => 1])->order('sort', 'desc')->select();
       /* $data = [
            [
                'id'    => 1,
                'title'    => '测试数据1',
            ],
            [
                'id'    => 2,
                'title'    => '测试数据2',
            ],
            [
                'id'    => 3,
                'title'    => '测试数据3',
            ],
        ];*/
        return message("操作成功", true, $data);
    }


    /**
     * 导出Excel
     * @throws \PHPExcel_Exception
     * @throws \PHPExcel_Reader_Exception
     * @throws \PHPExcel_Writer_Exception
     */
    public function exportExcel()
    {
        set_time_limit(0);
        $export_type = request()->param('export_type', 0);

        // 获取导出的数据源
        $res = $this->getList(1, 20000);
        $list = $res['data'];

        // 实例化PHPExcel类
        $objPHPExcel = new \PHPExcel();
        // 激活当前的sheet表
        $activeSheet = $objPHPExcel->setActiveSheetIndex(0);
        //5.设置表格头（即excel表格的第一行）
        $activeSheet->setCellValue('A1', '姓名')
            ->setCellValue('B1', '账号名称')
            ->setCellValue('C1', '角色')
            ->setCellValue('D1', '联系方式')
            ->setCellValue('E1', '所在省')
            ->setCellValue('F1', '所在市')
            ->setCellValue('G1', '所在县区')
            ->setCellValue('H1', '所在街道')
            ->setCellValue('I1', '所在学校')
            ->setCellValue('J1', '性别')
            ->setCellValue('K1', '创建时间');

        // 设置单元格宽度
        $activeSheet->getColumnDimension('A')->setWidth(20);
        $activeSheet->getColumnDimension('B')->setWidth(20);
        $activeSheet->getColumnDimension('C')->setWidth(20);
        $activeSheet->getColumnDimension('D')->setWidth(20);
        $activeSheet->getColumnDimension('E')->setWidth(20);
        $activeSheet->getColumnDimension('F')->setWidth(20);
        $activeSheet->getColumnDimension('G')->setWidth(20);
        $activeSheet->getColumnDimension('H')->setWidth(20);
        $activeSheet->getColumnDimension('I')->setWidth(20);
        $activeSheet->getColumnDimension('J')->setWidth(20);
        $activeSheet->getColumnDimension('K')->setWidth(20);

        //'s.*, schoole.title as schoole_name, grade.title as grade_name, class.title as class_name'
        // 循环刚取出来的数组，将数据逐一添加到excel表格
        $gender_arr = [
            '1' => '男',
            '2' => '女',
        ];
        for ($i = 0; $i < count($list); $i++) {
            $gender = $gender_arr[$list[$i]['gender']] ?? '';
            $activeSheet->setCellValue('A' . ($i + 2), $list[$i]['nickname']);
            $activeSheet->setCellValue('B' . ($i + 2), $list[$i]['username']);
            $activeSheet->setCellValue('C' . ($i + 2), $list[$i]['roles_name']);
            $activeSheet->setCellValue('D' . ($i + 2), $list[$i]['mobile']);
            $activeSheet->setCellValue('E' . ($i + 2), $list[$i]['province_name']);
            $activeSheet->setCellValue('F' . ($i + 2), $list[$i]['city_name']);
            $activeSheet->setCellValue('G' . ($i + 2), $list[$i]['district_name']);
            $activeSheet->setCellValue('H' . ($i + 2), $list[$i]['streets_name']);
            $activeSheet->setCellValue('I' . ($i + 2), $list[$i]['schoole_name']);
            $activeSheet->setCellValue('J' . ($i + 2), $gender);
            $activeSheet->setCellValue('K' . ($i + 2), date('Y-m-d H:i:s', $list[$i]['create_time']));
            $schoole_name = $list[$i]['schoole_name'];
        }
        // 设置保存的Excel表格名称
        $filename = '系统账号导出_' . date('YmdHis', time()) . ".xlsx";
        // 设置当前激活的sheet表格名称
        $activeSheet->setTitle('Sheet1');

        if($export_type) {//直接浏览器输出
            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            header('Content-Disposition: attachment;filename="' . $filename);
            header('Cache-Control: max-age=0');
            // If you're serving to IE 9, then the following may be needed
            header('Cache-Control: max-age=1');
            // If you're serving to IE over SSL, then the following may be needed
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
            header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
            header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
            header('Pragma: public'); // HTTP/1.0
            $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
            $objWriter->save('php://output');
            return;
        }

        // 保存本地文件
        $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
        $file_dir = UPLOAD_TEMP_PATH . "/user/";
        $savePath = $file_dir . $filename;
        // 检测文件路径是否存在,不存在则创建
        if (!file_exists($file_dir)) {
            mkdirs($file_dir, 0777, true);
        }
        $objWriter->save($savePath);

        // 文件地址
        $filePath = get_image_url(str_replace(PUBLIC_PATH, "", $savePath));
        return message("操作成功", true, $filePath);
    }

    public function delete()
    {
        // 参数
        $param = request()->param();

        // 记录ID
        $ids = getter($param, "id");
        if (empty($ids)) {
            return message("记录ID不能为空", false);
        }

        if (is_array($ids)) {
            if(in_array(1, $ids)) return message("超级管理员不可删除");
            // 批量删除
            $result = $this->model->deleteDAll($ids);
            if (!$result) {
                return message("批量删除失败", false);
            }

            return message("批量删除成功");
        } else {
            if($ids == 1) return message("超级管理员不可删除");
            // 单个删除
            $result = $this->model->drop($ids);
            if (!$result) {
                return message('删除失败', false);
            }

            return message('删除成功');
        }
    }

    public function sendSmsCode()
    {
        $param = request()->param();

        $phone = getter($param, "phone");
        if (empty($phone)) {
            return message("手机号码不能为空", false);
        }
        $pattern = "/^(?:(?:\+|00)86)?1\d{10}$/";
        if (!preg_match($pattern, $phone)) {
            return message("手机号码格式不正确", false);
        }
        $code = generate_sms_code();
        $config = new Config([
            "accessKeyId" => "LTAI5tPvgP5wTsww32SxjAVz",
            "accessKeySecret" => "7OzIBKy4EjLYUJLc5jx7keBv2UObjt"
        ]);
        $config->endpoint = "dysmsapi.aliyuncs.com";
        $client = new Dysmsapi($config);
        $request = new SendSmsRequest();
        $request->phoneNumbers = $phone;
        $request->templateCode = "SMS_469060333";
        $request->templateParam = "{\"code\":\"" . $code . "\"}";
        $request->signName = "广东揭阳精芯智能科技";
        /*$response = $client->sendSms($request);
        var_dump($response->toMap());*/
        $client->sendSms($request);
        $this->model->setCache($phone, $code, 180);

        return message("短信验证码发送成功");
    }

    public function verifySmsCode()
    {
        $param = request()->param();

        $phone = getter($param, "phone");
        if (!$phone) {
            return message("phone:手机号码不能为空", false);
        }
        $code = getter($param, "code");
        if (!$code) {
            return message("code:验证码不能为空", false);
        }
        $cache_code = $this->model->getCache($phone);
        if ($cache_code != $code) {
            return message("验证码不正确", false);
        }
        $this->model->setCache($phone . ":verify", true, 300);

        return message("手机号码验证成功");
    }

    public function appUserRegister()
    {
        $data = request()->param();
        $password = $data["password"] ?? '';
        if (!$password) {
            return message("密码不能为空", false);
        }
        // 密码长度必须在6-12位之间，且必须包含字母和数字
        $pattern = "/^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d]{6,12}$/";
        if (!preg_match($pattern, $password)) {
            return message("密码必须在6至12位且包含字母和数字", false);
        }
        $phone = $data["phone"] ?? '';
        $result = $this->model->getCache($phone . ":verify");
        if (!$result) {
            return message("手机号码未验证", false);
        }

        $data['gender'] = 0;
        $data['city'] = [];
        $data['role_ids'] = [11];
        $data['realname'] = "";
        $data['mobile'] = $phone;
        $data['nickname'] = $phone;
        $data['username'] = $phone;

        // 用户名
        $username = $phone;
        // 密码
        $password = trim($data['password']);
        //密码6-18位
        if(strlen($password)<6 || strlen($password)>18){
            return message("密码长度必须在6-18位之间", false);
        }
        $data['password'] = get_password($password . $username);
        // 用户名重复性验证
        $count = $this->model
            ->where("username", '=', $username)
            ->where("mark", "=", 1)
            ->count();
        if ($count > 0) {
            return message("此号码已注册", false);
        }

        // 头像处理
        $avatar = getter($data, 'avatar');
        if (!empty($avatar)) {
            if (strpos($avatar, "temp")) {
                $data['avatar'] = save_image($avatar, 'user');
            } else {
                $data['avatar'] = str_replace(IMG_URL, "", $data['avatar']);
            }
        } else {
            // 未设置头像时，默认头像
            $data['avatar'] = '/uploads/images/student/20240912/082d8f9214097758494f361813fa0907.png';
        }

        // 出生日期
        if (isset($data['birthday']) && $data['birthday']) {
            $data['birthday'] = strtotime($data['birthday']);
        }

        // 城市数据处理
        $city = isset($data['city']) ? $data['city'] : [];
        if (!empty($city)) {
            $data['province_code'] = $city[0];
            $data['city_code'] = $city[1];
            $data['district_code'] = $city[2];
        } else {
            $data['province_code'] = 0;
            $data['city_code'] = 0;
            $data['district_code'] = 0;
        }
        unset($data['city']);
        unset($data['id']);
        //用户类型：1=老师,2=学生家长
        $data['user_type'] = 2;

        $error = "";
        $result = $this->model->edit($data, $error);
        if (!$result) {
            return message($error, false);
        }

        // 删除用户整体缓存
        $this->model->cacheDAll();

        // 删除已存在的用户角色关系数据
        $userRoleService = new UserRoleService();
        $userRoleService->deleteUserRole($result);
        // 插入用户角色关系数据
        $userRoleService->insertUserRole($result, $data['role_ids']);

        $this->model->deleteCache($phone . ":verify");

        return message();
    }

    public function appUserForgetPwd()
    {
        // 获取参数
        $param = request()->param();
        // 新密码
        $newPassword = trim(getter($param, "newPassword"));
        if (!$newPassword) {
            return message("新密码不能为空", false);
        }
        // 密码长度必须在6-12位之间，且必须包含字母和数字
        $pattern = "/^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d]{6,12}$/";
        if (!preg_match($pattern, $newPassword)) {
            return message("密码必须在6至12位且包含字母和数字", false);
        }
        $phone = trim(getter($param, "phone"));
        $result = $this->model->getCache($phone . ":verify");
        if (!$result) {
            return message("手机号码未验证", false);
        }
        $userInfo = db('user')->where('username', $phone)->find();
        if (!$userInfo) {
            return message("用户信息不存在", false);
        }
        $newMd5Pwd = get_password($newPassword . $userInfo['username']);
        $item = [
            'id' => $userInfo['id'],
            'password' => $newMd5Pwd,
        ];
        $result = $this->model->edit($item);
        if (!$result) {
            return message("修改失败", false);
        }
        $this->model->deleteCache('pwd_raw:' . $userInfo['password']);
        $this->model->setCache('pwd_raw:' . $newMd5Pwd, $newPassword);
        return message("修改成功");
    }

    public function getAppUserInfo($userId)
    {
        $userInfo = $this->model->field('id,avatar,mobile,username,nickname')->where(['id' => $userId])->find();
        $userInfo['imeis'] = db('device_bind')->field('imei,is_admin,default_show,device_alias,relation')->where(['user_id' => $userId])->select();
        $defaultShowImei = db('device_bind')->field('imei')->where(['user_id' => $userId, 'default_show' => '1'])->find();
        if (empty($defaultShowImei) && !empty($userInfo['imeis'])) {
            $defaultShowImei = $userInfo['imeis'][0]['imei'];
            db('device_bind')->where(['user_id' => $userId, 'imei' => $defaultShowImei])->update(['default_show' => '1']);
            $userInfo['imeis'] = db('device_bind')->field('imei,is_admin,default_show,device_alias,relation')->where(['user_id' => $userId])->select();
        }
        // 家长端APP：补偿更新绑定设备imei与学生信息stu_id
        if (!empty($defaultShowImei)) {
            $student = Student::get(['imei' => $defaultShowImei]);
            if (!empty($student)) {
                $stu_id = $student->id;
                db('device_bind')->where(['user_id' => $userId, 'imei' => $defaultShowImei])->update(['stu_id' => $stu_id]);
            }
        }
        $imeiStuInfo = db('device_bind')->alias('bind')
            ->field('s.id as student_id,s.imei,s.avatar,s.name as student_name,s.student_no,s.id_card,s.gender,s.grade_id,s.class_id,s.schoole_id,s.phone,s.relatives_phone,s.sim_no, schoole.title as school_name, case grade.id when 1 then "一年级" when 2 then "二年级" when 3 then "三年级" when 4 then "四年级" when 5 then "五年级" when 6 then "六年级" end grade_name, concat(class.id,"班") as class_name')
            ->join('student s', 'bind.stu_id = s.id','inner')
            ->join('schoole schoole', 's.schoole_id = schoole.id', 'left')
            ->join('grade grade', 's.grade_id = grade.id', 'left')
            ->join('class class', 's.class_id = class.id', 'left')
            ->where(['bind.user_id' => $userId, 'bind.imei' => $defaultShowImei, 's.mark' => 1])->find();
        if (empty($imeiStuInfo)) {
            if (is_array($defaultShowImei)) {
                $defaultShowImei = implode('', $defaultShowImei);
            }
            $deviceId = substr($defaultShowImei, 4, 10);
            $deviceStuInfo = db('device_student_info_for_personal')->where('device_id', $deviceId)->find();
            // 如果缓存不存在就填充空字符串
            if (empty($deviceStuInfo)) {
                $imeiStuInfo['student_id'] = 0;
                $imeiStuInfo['student_name'] = '';
                $imeiStuInfo['school_name'] = '';
                $imeiStuInfo['grade_name'] = '';
                $imeiStuInfo['class_name'] = '';
            } else {
                $imeiStuInfo = $deviceStuInfo;
            }
        } else {
            if (is_array($defaultShowImei)) {
                $defaultShowImei = implode('', $defaultShowImei);
            }
            $deviceId = substr($defaultShowImei, 4, 10);
            $imeiStuInfo['device_id'] = $deviceId;
        }
        $userInfo['imeiStuInfo'] = $imeiStuInfo;
        return message("操作成功", true, $userInfo);
    }

    public function getMiniAppUserInfo($userId)
    {
        $userInfo = db('user')->alias('u')
            ->field('u.id,u.avatar,u.mobile,u.username,u.nickname,s.title as school_name')
            ->join('schoole s', 'u.schoole_id = s.id', 'left')
            ->where(['u.id' => $userId])->find();
        return message("操作成功", true, $userInfo);
    }

    public function updateAvatar($userId)
    {
        // 获取参数
        $param = request()->param();
        // 原始密码
        $avatarUrl = trim(getter($param, "avatarUrl"));
        if (!$avatarUrl) {
            return message("头像地址不能为空", false);
        }
        $userInfo = $this->model->getInfo($userId);
        if (!$userInfo) {
            return message("用户信息不存在", false);
        }
        $item = [
            'id' => $userId,
            'avatar' => $avatarUrl,
        ];
        $result = $this->model->edit($item);
        if (!$result) {
            return message("修改失败", false);
        }
        return message("修改成功");
    }

    public function updateNickname($userId)
    {
        // 获取参数
        $param = request()->param();
        $nickname = getter($param, "nickname");
        if (!$nickname) {
            return message("更改用户昵称不能为空", false);
        }
        if (mb_strlen($nickname, 'utf-8') > 10) {
            return message("昵称长度不能超过10个字符", false);
        }
        $userInfo = $this->model->getInfo($userId);
        if (!$userInfo) {
            return message("用户信息不存在", false);
        }
        $item = [
            'id' => $userId,
            'nickname' => $nickname,
        ];
        $result = $this->model->edit($item);
        if (!$result) {
            return message("修改失败", false);
        }
        return message("修改成功");
    }

    public function updateMobile($userId)
    {
        // 获取参数
        $param = request()->param();
        $mobile = getter($param, "mobile");
        if (empty($mobile)) {
            return message("手机号码不能为空", false);
        }
        $result = $this->model->getCache($mobile . ":verify");
        if (!$result) {
            return message("手机号码未验证", false);
        }
        $userInfo = db('user')->where('id', $userId)->find();
        if (!$userInfo) {
            return message("用户信息不存在", false);
        }
        if ($userInfo['mobile'] == $mobile) {
            return message("新号码与原号码一致，无需修改", false);
        }
        $pwdRaw = $this->model->getCache('pwd_raw:' . $userInfo['password']);
        $newMd5Pwd = get_password($pwdRaw . $mobile);
        $item = [
            'id' => $userId,
            'mobile' => $mobile,
            'username' => $mobile,
            'password' => $newMd5Pwd,
        ];
        $result = $this->model->edit($item);
        if (!$result) {
            return message("修改失败", false);
        }
        // 由于密码与username有强关联性，所以修改手机号相当于改变账号登录名和密码
        $this->model->deleteCache('pwd_raw' . $userInfo['password']);
        $this->model->setCache('pwd_raw:' . $newMd5Pwd, $pwdRaw);
        return message("修改成功");
    }

    public function checkUser()
    {
        $data = request()->param();
        $username = getter($data, "username");
        $id = $data['id'] ?? '';
        if (!$username) {
            return message("账号名称不能为空", false);
        }
        if (!$id) {
            $count = $this->model
                ->where("username", '=', $username)
                ->where("mark", "=", 1)
                ->count();
        } else {
            $count = $this->model
                ->where("username", '=', $username)
                ->where("id", "<>", $id)
                ->where("mark", "=", 1)
                ->count();
        }
        if ($count > 0) {
            return message("账号名称已存在", false);
        }
        return message("账号名称可用", true, []);
    }
}